package com.hmdp.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.json.JSON;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmdp.dto.Result;
import com.hmdp.entity.ShopType;
import com.hmdp.mapper.ShopTypeMapper;
import com.hmdp.service.IShopTypeService;
import com.hmdp.utils.RedisConstants;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.hmdp.utils.RedisConstants.CACHE_SHOP_TYPE_KEY;
import static com.hmdp.utils.RedisConstants.CACHE_SHOP_TYPE_TTL;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 虎哥
 * @since 2021-12-22
 */
@Service
public class ShopTypeServiceImpl extends ServiceImpl<ShopTypeMapper, ShopType> implements IShopTypeService {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public Result listShopType() {
        String key = CACHE_SHOP_TYPE_KEY;
        //1. 查询Redis有无缓存
        List<String> shopTypeJsons = stringRedisTemplate.opsForList().range(key, 0, -1);
        //检查缓存是否为空
        if (!CollectionUtil.isEmpty(shopTypeJsons)) {
            //2.命中，就要用，就直接返回，  但是呢！！要转成list形式
            List<ShopType> shopTypeList = shopTypeJsons.stream()
                    .map(item -> JSONUtil.toBean(item, ShopType.class))
                    //根据sort字段升序排列
                    .sorted(Comparator.comparingInt(ShopType::getSort))
                    .collect(Collectors.toList());
            //返回缓存数据
            return Result.ok(shopTypeList);
        }
        //3.未命中（空），查询数据库
        List<ShopType> shopTypes = lambdaQuery().orderByAsc(ShopType::getSort).list();
        //4.判断数据库中是否有数据
        if (CollectionUtil.isEmpty(shopTypes)) {
            //5.无数据，返回错误
            //但还要缓存一个空集合，解决缓存穿透
            stringRedisTemplate.opsForValue().set(key, Collections.emptyList().toString(),CACHE_SHOP_TYPE_TTL, TimeUnit.MINUTES);
            return Result.fail("商铺分类信息为空：");
        }
        //有数据,先写入缓存再返回
        //6.使用stream流bean集合转为json集合
        //将从数据库查询到的list转化为String Json形式 存放到Redis中
        List<String> shopTypeCache = shopTypes.stream()
                .sorted(Comparator.comparingInt(ShopType::getSort))
                .map(JSONUtil::toJsonStr)
                .collect(Collectors.toList());
        //7.存入缓存中,此处只能使用右插入，因为要保证顺序
        stringRedisTemplate.opsForList().rightPushAll(CACHE_SHOP_TYPE_KEY, shopTypeCache);
        stringRedisTemplate.expire(CACHE_SHOP_TYPE_KEY, CACHE_SHOP_TYPE_TTL, TimeUnit.MINUTES);
        //返回数据库数据
        return Result.ok(shopTypes);
    }
}
